package com.liuhongwei.test.builder;


import com.liuhongwei.test.bean.Constants;
import com.liuhongwei.test.bean.FieldInfo;
import com.liuhongwei.test.bean.TableInfo;
import com.liuhongwei.test.utils.DateUtils;
import com.liuhongwei.test.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

public class BuildPo {

    private static final Logger log = LoggerFactory.getLogger(BuildPo.class);


    public static void execute(TableInfo tableInfo) {
        File folder = new File(Constants.PATH_PO);
        if (!folder.exists()) {
            folder.mkdirs();
        }

        OutputStream os = null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;
        try {
            os = Files.newOutputStream(Paths.get(folder + "/" + tableInfo.getBeanName() + ".java"));
            osw = new OutputStreamWriter(os, StandardCharsets.UTF_8);
            bw = new BufferedWriter(osw);

            bw.write("package " + Constants.PACKAGE_PO + ";\n\n");
            //写入Import
            writeImport(tableInfo, bw);
            //写入类注释
            BuildComment.createClassComment(bw, tableInfo.getComment());
            bw.write("public class " + tableInfo.getBeanName() + " implements Serializable {\n\n");

            //写入属性
            writeField(tableInfo, bw);

            //写入getter、setter
            writeGetterSetter(tableInfo, bw);

            //重写toString方法
            writeToString(tableInfo, bw);

            bw.write("}");
            bw.flush();
        } catch (Exception e) {
            log.error("创建po失败", e);
        } finally {
            BuildBase.close(os, osw, bw);
        }
    }

    private static void writeToString(TableInfo tableInfo, BufferedWriter bw) throws IOException {
        StringBuffer toString = new StringBuffer();
        toString.append("\"");
        String s = "\n" + "\t" + " + \"," ;
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            String comment = fieldInfo.getComment();
            String propertyName = fieldInfo.getPropertyName();
            String propertyName2 = fieldInfo.getPropertyName();
            if (haveDateTimeTypes(fieldInfo)) {
                propertyName2 =
                        "DateUtils.format(" + propertyName + ", DateUtils.YYYY_MM_DD_HH_MM_SS)";
            } else if (haveDateTypes(fieldInfo)) {
                propertyName2 = "DateUtils.format(" + propertyName + ", DateUtils.YYYY_MM_DD)";
            }
            toString.append(comment + ":\" + (" + propertyName + " == null ? \"空\" : " + propertyName2 + ")" + s);
        }
        toString.delete(toString.length() - s.length(), toString.length());
        bw.write("\t@Override\n");
        bw.write("\tpublic String toString() {\n");
        bw.write("\t\treturn " + toString + ";\n");
        bw.write("\t}\n");
        bw.newLine();
    }

    private static void writeGetterSetter(TableInfo tableInfo, BufferedWriter bw) throws IOException {
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            String javaType = fieldInfo.getJavaType();
            String propertyName = fieldInfo.getPropertyName();
            String tempField = StringUtils.upperCaseFirst(propertyName);
            bw.write("\tpublic void set" + tempField + "(" + javaType + " " + propertyName + ") {\n");
            bw.write("\t\tthis." + propertyName + " = " + propertyName + ";\n");
            bw.write("\t}\n");
            bw.newLine();

            bw.write("\tpublic " + javaType + " get" + tempField + "() {\n");
            bw.write("\t\treturn " + propertyName + ";\n");
            bw.write("\t}\n");
            bw.newLine();
        }
        bw.newLine();
    }

    private static void writeField(TableInfo tableInfo, BufferedWriter bw) throws Exception {
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            BuildComment.createFieldComment(bw, fieldInfo.getComment());

            if (haveDateTimeTypes(fieldInfo)) {
                writeDate(bw, DateUtils.YYYY_MM_DD_HH_MM_SS);
            }
            if (haveDateTypes(fieldInfo)) {
                writeDate(bw, DateUtils.YYYY_MM_DD);
            }
            if (haveIgnoreFiled(fieldInfo)) {
                bw.write("\t" + Constants.IGNORE_BEAN_TOJSON_EXPRESSION + "\n");
            }

            bw.write("\tprivate " + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + ";" + "\n\n");
        }
        bw.newLine();
    }

    private static void writeImport(TableInfo tableInfo, BufferedWriter bw) throws IOException {
        bw.write("import java.io.Serializable;\n");
        if (tableInfo.getHaveBigDecimal()) {
            bw.write("import java.math.BigDecimal;\n");
        }
        if (tableInfo.getHaveDate() || tableInfo.getHaveDateTime()) {
            bw.write("import java.util.Date;\n");
            bw.write(Constants.BEAN_DATE_FORMAT_CLASS + ";\n");
            bw.write(Constants.BEAN_DATE_UNFORMAT_CLASS + ";\n");
            bw.write("import " + Constants.PACKAGE_UTILS + ".DateUtils;\n");
        }
        Boolean haveIgnoreBean = false;
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            if (haveIgnoreFiled(fieldInfo)) {
                haveIgnoreBean = true;
                break;
            }
        }
        if (haveIgnoreBean) {
            bw.write(Constants.IGNORE_BEAN_TOJSON_CLASS + ";\n");
        }
    }

    private static Boolean haveIgnoreFiled(FieldInfo fieldInfo) {
        return Arrays.asList(Constants.IGNORE_BEAN_TOJSON_FILED.split(",")).contains(fieldInfo.getPropertyName());
    }

    private static Boolean haveDateTimeTypes(FieldInfo fieldInfo) {
        return Constants.SQL_DATE_TIME_TYPES.contains(fieldInfo.getSqlType());
    }

    private static Boolean haveDateTypes(FieldInfo fieldInfo) {
        return Constants.SQL_DATE_TYPES.contains(fieldInfo.getSqlType());
    }

    private static void writeDate(BufferedWriter bw, String formDate) throws IOException {
        bw.write("\t" + String.format(Constants.BEAN_DATE_FORMAT_EXPRESSION, formDate) + "\n");
        bw.write("\t" + String.format(Constants.BEAN_DATE_UNFORMAT_EXPRESSION, formDate) + "\n");
    }


    public static void main(String[] args) {
        List<TableInfo> tableInfoList = BuildTable.getTable();
        for (TableInfo tableInfo : tableInfoList) {
            BuildPo.execute(tableInfo);
        }
    }
}
